/* * Copyright 2003-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.attributes; import java.lang.reflect.Field; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.HashSet; import java.util.HashMap; /** * * @since 2.1 */ class DefaultCachedRepository implements CachedRepository { private final static Collection EMPTY_COLLECTION = new ArrayList (0); private final Collection classAttributes; private final Map fields = new HashMap (); private final Map methods = new HashMap (); private final Map constructors = new HashMap (); private static class MethodAttributeBundle { private Collection attributes = EMPTY_COLLECTION; private List parameterAttributes = new ArrayList (); private Collection returnAttributes = EMPTY_COLLECTION; private final String methodName; public MethodAttributeBundle (String methodName) { this.methodName = methodName; } public Collection getAttributes () { return attributes; } public Collection getReturnAttributes () { return returnAttributes; } public Collection getParameterAttributes (int index) { if (index < 0 || index >= parameterAttributes.size ()) { throw new ParameterIndexOutOfBoundsException (methodName, index, parameterAttributes.size ()); } return (Collection) parameterAttributes.get (index); } public void setAttributes (Collection attributes) { this.attributes = Collections.unmodifiableCollection (attributes); } public void setReturnAttributes (Collection returnAttributes) { this.returnAttributes = Collections.unmodifiableCollection (returnAttributes); } public void addParameterAttributes (Collection parameterAttributes) { this.parameterAttributes.add (Collections.unmodifiableCollection (parameterAttributes)); } } public DefaultCachedRepository (Class clazz, AttributeRepositoryClass repo) { // ---- Fix up class attributes Set tempClassAttributes = new HashSet (); tempClassAttributes.addAll (repo.getClassAttributes ()); tempClassAttributes.addAll (getInheritableClassAttributes (clazz.getSuperclass ())); Class[] ifs = clazz.getInterfaces (); for (int i = 0; i < ifs.length; i++) { tempClassAttributes.addAll (getInheritableClassAttributes (ifs[i])); } this.classAttributes = Collections.unmodifiableCollection (tempClassAttributes); // ---- Fix up method attributes Method[] methods = clazz.getDeclaredMethods (); for (int i = 0; i < methods.length; i++) { Method m = methods[i]; String key = Util.getSignature (m); MethodAttributeBundle bundle = new MethodAttributeBundle (m.toString ()); List attributeBundle = null; if (repo.getMethodAttributes ().containsKey (key)) { attributeBundle = (List) repo.getMethodAttributes ().get (key); } Set attributes = new HashSet (); if (attributeBundle != null) { attributes.addAll ((Collection) attributeBundle.get (0)); } attributes.addAll (getInheritableMethodAttributes (clazz.getSuperclass (), m.getName (), m.getParameterTypes ())); for (int j = 0; j < ifs.length; j++) { attributes.addAll (getInheritableMethodAttributes (ifs[j], m.getName (), m.getParameterTypes ())); } if (attributes.size () > 0) { bundle.setAttributes (attributes); } // ---- Return value attributes attributes = new HashSet (); if (attributeBundle != null) { attributes.addAll ((Collection) attributeBundle.get (1)); } attributes.addAll (getInheritableReturnAttributes (clazz.getSuperclass (), m.getName (), m.getParameterTypes ())); for (int j = 0; j < ifs.length; j++) { attributes.addAll (getInheritableReturnAttributes (ifs[j], m.getName (), m.getParameterTypes ())); } if (attributes.size () > 0) { bundle.setReturnAttributes (attributes); } // ---- Parameter attributes int numParameters = m.getParameterTypes().length; for (int k = 0; k < numParameters; k++) { attributes = new HashSet (); if (attributeBundle != null) { attributes.addAll ((Collection) attributeBundle.get (k + 2)); } attributes.addAll (getInheritableMethodParameterAttributes (clazz.getSuperclass (), m.getName (), m.getParameterTypes (), k)); for (int j = 0; j < ifs.length; j++) { attributes.addAll (getInheritableMethodParameterAttributes (ifs[j], m.getName (), m.getParameterTypes (), k)); } bundle.addParameterAttributes (attributes); } this.methods.put (m, bundle); } // --- Just copy constructor attributes (they aren't inherited) Constructor[] constructors = clazz.getDeclaredConstructors (); for (int i = 0; i < constructors.length; i++) { Constructor ctor = constructors[i]; String key = Util.getSignature (ctor); if (repo.getConstructorAttributes ().containsKey (key)) { List attributeBundle = null; attributeBundle = (List) repo.getConstructorAttributes ().get (key); MethodAttributeBundle bundle = new MethodAttributeBundle (ctor.toString ()); bundle.setAttributes ((Collection) attributeBundle.get (0)); // ---- Parameter attributes int numParameters = ctor.getParameterTypes().length; for (int k = 0; k < numParameters; k++) { bundle.addParameterAttributes ((Collection) attributeBundle.get (k + 1)); } this.constructors.put (ctor, bundle); } } // --- Just copy field attributes (they aren't inherited) Field[] fields = clazz.getDeclaredFields (); for (int i = 0; i < fields.length; i++) { Field f = fields[i]; String key = f.getName (); if (repo.getFieldAttributes ().containsKey (key)) { this.fields.put (f, Collections.unmodifiableCollection ((Collection) repo.getFieldAttributes ().get (key))); } } } private static Collection getInheritableAttributes (Collection attrs) { HashSet result = new HashSet (); Iterator iter = attrs.iterator (); while (iter.hasNext ()) { Object attr = iter.next (); if (Attributes.hasAttributeType (attr.getClass (), Inheritable.class)) { result.add (attr); } } return result; } private static Collection getInheritableClassAttributes (Class c) { if (c == null) { return new ArrayList (0); } HashSet result = new HashSet (); result.addAll (getInheritableAttributes (Attributes.getAttributes (c))); // Traverse the class hierarchy result.addAll (getInheritableClassAttributes (c.getSuperclass ())); // Traverse the interface hierarchy Class[] ifs = c.getInterfaces (); for (int i = 0; i < ifs.length; i++) { result.addAll (getInheritableClassAttributes (ifs[i])); } return result; } private static Collection getInheritableMethodAttributes (Class c, String methodName, Class[] methodParams) { if (c == null) { return new ArrayList (0); } HashSet result = new HashSet (); try { // Get equivalent method in c Method m = c.getDeclaredMethod (methodName, methodParams); if ((m.getModifiers () & Modifier.PRIVATE) == 0) { result.addAll (getInheritableAttributes (Attributes.getAttributes (m))); } } catch (NoSuchMethodException nsme) { } // Traverse the class hierarchy result.addAll (getInheritableMethodAttributes (c.getSuperclass (), methodName, methodParams)); // Traverse the interface hierarchy Class[] ifs = c.getInterfaces (); for (int i = 0; i < ifs.length; i++) { result.addAll (getInheritableMethodAttributes (ifs[i], methodName, methodParams)); } return result; } private static Collection getInheritableMethodParameterAttributes (Class c, String methodName, Class[] methodParams, int parameter) { if (c == null) { return new ArrayList (0); } HashSet result = new HashSet (); try { // Get equivalent method in c Method m = c.getDeclaredMethod (methodName, methodParams); if ((m.getModifiers () & Modifier.PRIVATE) == 0) { result.addAll (getInheritableAttributes (Attributes.getParameterAttributes (m, parameter))); } } catch (NoSuchMethodException nsme) { } // Traverse the class hierarchy result.addAll (getInheritableMethodParameterAttributes (c.getSuperclass (), methodName, methodParams, parameter)); // Traverse the interface hierarchy Class[] ifs = c.getInterfaces (); for (int i = 0; i < ifs.length; i++) { result.addAll (getInheritableMethodParameterAttributes (ifs[i], methodName, methodParams, parameter)); } return result; } private static Collection getInheritableReturnAttributes (Class c, String methodName, Class[] methodParams) { if (c == null) { return new ArrayList (0); } HashSet result = new HashSet (); try { // Get equivalent method in c Method m = c.getDeclaredMethod (methodName, methodParams); if ((m.getModifiers () & Modifier.PRIVATE) == 0) { result.addAll (getInheritableAttributes (Attributes.getReturnAttributes (m))); } } catch (NoSuchMethodException nsme) { } // Traverse the class hierarchy result.addAll (getInheritableReturnAttributes (c.getSuperclass (), methodName, methodParams)); // Traverse the interface hierarchy Class[] ifs = c.getInterfaces (); for (int i = 0; i < ifs.length; i++) { result.addAll (getInheritableReturnAttributes (ifs[i], methodName, methodParams)); } return result; } public Collection getAttributes () { return classAttributes; } public Collection getAttributes (Field f) { if (fields.containsKey (f)) { return (Collection) fields.get (f); } else { return EMPTY_COLLECTION; } } public Collection getAttributes (Method m) { if (methods.containsKey (m)) { return ((MethodAttributeBundle) methods.get (m)).getAttributes (); } else { return EMPTY_COLLECTION; } } public Collection getParameterAttributes (Constructor c, int parameter) { if (constructors.containsKey (c)) { return ((MethodAttributeBundle) constructors.get (c)).getParameterAttributes (parameter); } else { return EMPTY_COLLECTION; } } public Collection getParameterAttributes (Method m, int parameter) { if (methods.containsKey (m)) { return ((MethodAttributeBundle) methods.get (m)).getParameterAttributes (parameter); } else { return EMPTY_COLLECTION; } } public Collection getReturnAttributes (Method m) { if (methods.containsKey (m)) { return ((MethodAttributeBundle) methods.get (m)).getReturnAttributes (); } else { return EMPTY_COLLECTION; } } public Collection getAttributes (Constructor c) { if (constructors.containsKey (c)) { return ((MethodAttributeBundle) constructors.get (c)).getAttributes (); } else { return EMPTY_COLLECTION; } } }